package mips.instructions;

/**
 * <code>LWL</code> instruction<br/>
 * Load Word Left<br/>
 * @author jnmartin84@gmail.com
 */
public class LWL extends Instruction {

	private static final LWL instance = new LWL();
	private static final String insName = "LWL";

	private LWL(){}

	public static LWL getInstance() {
		return instance;
	}

	/**
	 * <b>Format:</b><br/>
	 * LWL rt, offset(base)<br/><br/>
	 * <b>Description:</b><br/>
	 * This instruction can be used in combination with the LWR instruction to<br/>
	 * load a register with four consecutive bytes from memory, when the bytes<br/>
	 * cross a word boundary. LWL loads the left portion of the register with the<br/>
	 * appropriate part of the high-order word; LWR loads the right portion of<br/>
	 * the register with the appropriate part of the low-order word.<br/><br/>
	 * The LWL instruction adds its sign-extended 16-bit offset to the contents of<br/>
	 * general register base to form a virtual address which can specify an<br/>
	 * arbitrary byte. It reads bytes only from the word in memory which<br/>
	 * contains the specified starting byte. From one to four bytes will be loaded,<br/>
	 * depending on the starting byte specified. In 64-bit mode, the loaded word<br/>
	 * is sign-extended.<br/><br/>
	 * Conceptually, it starts at the specified byte in memory and loads that byte<br/>
	 * into the high-order (left-most) byte of the register; then it loads bytes from<br/>
	 * memory into the register until it reaches the low-order byte of the word in<br/>
	 * memory. The least-significant (right-most) byte(s) of the register will not<br/>
	 * be changed.<br/>
	 */
	@Override
	public final void execute(final int instruction) {
		
		// "base"
		final int rs = (instruction >> 21) & 0x0000001F;
		final int rt = (instruction >> 16) & 0x0000001F;
		final int offset = Instruction.signExtendH(instruction & 0x0000FFFF) << 2;
		
		final int startByte = offset % 4;
		
		// double-check this works right!
		int writeword = (int) (mips.R4300i.GPR[rt] & 0x00000000FFFFFFFFL);
		
		// test this some time to make sure its actually right
		for(int i=startByte;i<4;i++) {
			
			// double-check this works right!
			int bite = n64.MemoryManager.readByte((int)(mips.R4300i.GPR[rs] & 0x00000000FFFFFFFFL) + offset + i);
			writeword &= (bite << (3 - startByte));			
		}
		
		mips.R4300i.PC = mips.R4300i.nPC;
		mips.R4300i.nPC = mips.R4300i.nPC + 4;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String emit(final int instruction) {
		return	"";
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getName(final int instruction) {
		return getName();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getName() {
		return insName;
	}
}